use common_base::prelude::*;
use common_core::{
    data::{BizMetadata, FormDataModel, Metadata},
    ServiceContext, ServiceContextBase,
};

#[derive(Debug)]
pub struct FormContext {
    pub(crate) service_context_base: ServiceContextBase,
    pub(crate) biz_metadata: Option<Metadata>,
    pub(crate) form_data_model: Option<SharedRef<FormDataModel>>,
}

// this is dangerous because `SharedRef` must not used between threads
unsafe impl Send for FormContext {}

impl FormContext {
    pub fn get_instance(service_context_base: ServiceContextBase) -> Self {
        Self {
            service_context_base,
            biz_metadata: None,
            form_data_model: None,
        }
    }

    #[inline]
    pub fn downcast_from(srv_ctx: &dyn ServiceContext) -> Result<&FormContext> {
        srv_ctx
            .as_any()
            .downcast_ref::<FormContext>()
            .ok_or(ErrorCode::PluginParamTypeInvalid(
                "expect FormContext but not.",
            ))
    }

    #[inline]
    pub fn downcast_from_mut(srv_ctx: &mut dyn ServiceContext) -> Result<&mut FormContext> {
        srv_ctx
            .as_any_mut()
            .downcast_mut::<FormContext>()
            .ok_or(ErrorCode::PluginParamTypeInvalid(
                "expect FormContext but not.",
            ))
    }
}

impl ServiceContext for FormContext {
    fn get_service_context_base(&self) -> &ServiceContextBase {
        &self.service_context_base
    }
    fn get_service_context_base_mut(&mut self) -> &mut ServiceContextBase {
        &mut self.service_context_base
    }

    fn as_any(&self) -> &dyn std::any::Any {
        self
    }
    fn as_any_mut(&mut self) -> &mut dyn std::any::Any {
        self
    }
}
